<template>
    <div class="main">
        <div ref="sceneNode" class="scene">
        </div>
    </div>
</template>

<script setup name="ModelView">
/**
 * @author zhaojiuyi
 * @date 2023/6/22
 * */
import {
    AxesHelper,
    AmbientLight,
    WebGLRenderer,
    Fog,
    GridHelper,
    Mesh,
    Clock,
    Scene,
    MeshStandardMaterial,
    PerspectiveCamera,
    PlaneGeometry,
    PointLight,
    Color,
    BoxGeometry,
    MeshPhysicalMaterial,
    PointLightHelper,
    TorusGeometry,
    MeshBasicMaterial,
    SpotLight,
    SphereGeometry, RectAreaLight, AnimationMixer
} from "three"
import {OrbitControls} from 'three/addons/controls/OrbitControls.js';
import {onMounted, onUnmounted, ref} from "vue";
import {GLTFLoader} from "three/examples/jsm/loaders/GLTFLoader";
import {gsap} from "gsap"
// import {RectAreaLightHelper} from "three/addons/helpers/RectAreaLightHelper";

let timer = null
let gblModel = null
let animationMixer= null
const sceneNode = ref()

// 渲染器
const renderer = new WebGLRenderer({antialias: true})
renderer.shadowMap.enabled = true

// 场景
const scene = new Scene()
// scene.fog = new Fog(0xcccccc, 5, 100);

// 相机
const camera = new PerspectiveCamera()
camera.position.set(50,20,50)

// 坐标轴
const axesHelper = new AxesHelper(1000)
scene.add(axesHelper)

// 环境光
const ambientLight = new AmbientLight(0xffffff, 1); // 柔和的白光
scene.add(ambientLight);

// 点光源
const pointLight = new PointLight(0xffffff, 5, 80);
pointLight.position.set(0, 40, 10);
pointLight.castShadow = true
pointLight.shadow.mapSize.width = 5000
pointLight.shadow.mapSize.height = 5000
pointLight.shadow.camera.near = 0.5
pointLight.shadow.camera.far = 5
scene.add(pointLight);

const helper = new PointLightHelper(pointLight, 1);
scene.add(helper);

const rectLight = new RectAreaLight( 0xffffff, 1, 500, 500 );
rectLight.position.set( 0, 0, 500 );
rectLight.lookAt( 0, 0, 0 );
scene.add( rectLight )
gsap.to(rectLight.position, {
    duration: 2.5,
    ease: "power2.out",
    z: -500,
    // scale: 3,
    repeat: -1,
    yoyo: true
})
// const rectLightHelper = new RectAreaLightHelper( rectLight );
// scene.add( rectLightHelper );
// const torusGeometry = new TorusGeometry(1, 0.2, 10, 50)
// // const sphereGeometry = new SphereGeometry(0,32,16)
// const torusMaterial = new MeshBasicMaterial({
//     color: 0xff0000,
//     opacity: 1,
//     transparent: true
// })
// const torus = new Mesh(torusGeometry, torusMaterial)
// torus.position.set(0,50,1)
// torus.rotation.x = -Math.PI /2
// const spotLight = new SpotLight(0xff0000)
// spotLight.castShadow = true
// torus.add(spotLight)
// gsap.to(torus.position, {
//     duration: 2.5,
//     ease: "power2.out",
//     y: 0,
//     // scale: 3,
//     repeat: -1,
//     yoyo: true
// })
// scene.add(torus)
//
// const sphereGeometry = new SphereGeometry(1,32,16)
// const sphereMaterial = new MeshBasicMaterial({
//     color: 0x000000,
//     opacity: 1,
//     transparent: true
// })
// const sphere = new Mesh(sphereGeometry, sphereMaterial)
// sphere.position.set(0,50,0)
// gsap.to(sphere.position, {
//     duration: 2.5,
//     ease: "power2.out",
//     y: 0,
//     scale: 3,
//     repeat: -1,
//     yoyo: true
// })
// scene.add(sphere)


// 地面
const geometry = new PlaneGeometry(500, 500, 10, 10);
const material = new MeshStandardMaterial({color: 0x6e6e6e});
const circle = new Mesh(geometry, material);
circle.rotation.x = -Math.PI / 2.0;
circle.receiveShadow = true
scene.add(circle);

// 地面网格
const gridHelper = new GridHelper(500, 200);
scene.add(gridHelper);

// 轨道控制器
const controls = new OrbitControls(camera, renderer.domElement)

// 盒子
const boxGeometry = new BoxGeometry(1, 1, 1)
const standMaterial = new MeshPhysicalMaterial({color: new Color("gray")})
const cube = new Mesh(boxGeometry, standMaterial)
cube.position.set(-1, 0.5, 0)
cube.castShadow = true
cube.receiveShadow = true
cube.emissive = 0xffffff
cube.material.metalness = .8
cube.material.roughness = .4
scene.add(cube)

// 时钟
const clock = new Clock()
const render = () => {
    renderer.render(scene, camera)
    controls.update();
    if (animationMixer) {
        animationMixer.update(clock.getDelta())
    }
    timer = requestAnimationFrame(render)
}

const createModel = () => {
    const loader = new GLTFLoader()
    return new Promise((resolve, reject) => {
        loader.load('/models/Parrot.glb', glb => {
                resolve(glb)
            }, () => {
            },
            err => {
                reject()
            })
    })
}

onMounted(async () => {
    const sceneDom = sceneNode.value
    renderer.setSize(sceneDom.clientWidth, sceneDom.clientHeight)
    sceneDom.innerHTML = null
    sceneDom.appendChild(renderer.domElement)

    gblModel = await createModel()
    gblModel.scene.position.set(0,20,0)
    gblModel.scene.traverse(e => {
        if (e.isMesh) {
            e.castShadow = true
            e.receiveShadow = true
        }
    })
    scene.add(gblModel.scene)
    animationMixer = new AnimationMixer(gblModel.scene)
    animationMixer.clipAction(gblModel.animations[0]).play()
    render()
})

onUnmounted(() => {
    cancelAnimationFrame(timer)
})


</script>
<style>
.main {
    width: 100vw;
    height: 100vh;
    overflow: hidden;
    display: flex;

}

.scene {
    flex-grow: 3;
    flex-shrink: 0;
    flex-basis: 0;
}

.control {
    flex-grow: 1;
    flex-shrink: 0;
    flex-basis: 0;
}
</style>

